package overweight

import (
	"adam2/internal/model"
	"adam2/internal/properties"
	"adam2/internal/util"
	"anubis-framework/pkg/io"
	"gorm.io/gorm"
)

// 根据牛熊线加仓
type BullShortLineOverweight struct {
	db *gorm.DB
}

// 初始化
func (b *BullShortLineOverweight) Init(db *gorm.DB) {
	b.db = db
}

// 执行，返回值为true表示已经加仓，否则为false
func (b *BullShortLineOverweight) Exec(transactionDate string) {
	io.Infoln("根据牛熊线加仓，日期[%s]", transactionDate)

	// 是否加仓了
	//var overweight bool = false

	var quantAccountLogArray *model.QuantAccountLogArray = &model.QuantAccountLogArray{}
	b.db.Raw("select * from quant_account_log t where t.date_=to_date(?, 'yyyy-mm-dd')", transactionDate).Scan(quantAccountLogArray)

	if nil != quantAccountLogArray && len(*quantAccountLogArray) > 0 {
		for _, quantAccountLog := range *quantAccountLogArray {
			// 如果对应账号的仓位已满，则不用再加仓
			var optimizeAccount *model.OptimizeAccount = &model.OptimizeAccount{}
			b.db.Raw("select * from optimize_account t where t.account_name=?", quantAccountLog.AccountName).Scan(optimizeAccount)
			if optimizeAccount.HoldStockNumber == properties.QuantProperties_.MaxHoldStockNumber {
				continue
			}

			// 表示牛熊线
			var bullShortLine float64
			// 是否在牛熊线之上
			var aboveBullShortLine bool = false
			if !aboveBullShortLine && quantAccountLog.Bias250 != 0 && quantAccountLog.Bias250 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias250 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma250
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			if !aboveBullShortLine && quantAccountLog.Bias120 != 0 && quantAccountLog.Bias120 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias120 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma120
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			if !aboveBullShortLine && quantAccountLog.Bias60 != 0 && quantAccountLog.Bias60 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias60 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma60
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			if !aboveBullShortLine && quantAccountLog.Bias20 != 0 && quantAccountLog.Bias20 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias20 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma20
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			if !aboveBullShortLine && quantAccountLog.Bias10 != 0 && quantAccountLog.Bias10 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias10 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma10
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			if !aboveBullShortLine && quantAccountLog.Bias5 != 0 && quantAccountLog.Bias5 <= properties.QuantProperties_.BiasThresholdTop && quantAccountLog.Bias5 >= properties.QuantProperties_.BiasThresholdBottom {
				bullShortLine = quantAccountLog.Ma5
				if quantAccountLog.TotalAssets >= bullShortLine {
					aboveBullShortLine = true
				}
			}
			// 如果最后任何bias指标都无法确定哪一根均线可以作为牛熊线的话，则将前一个交易日的总资产作为牛熊线
			b.db.Raw("select t1.total_assets from (select * from quant_account_log t where t.account_name=? and t.date_<to_date(?, 'yyyy-mm-dd') order by t.date_ desc) t1 "+
				"where rownum<=1", quantAccountLog.AccountName, transactionDate).Scan(&bullShortLine)
			if quantAccountLog.TotalAssets >= bullShortLine {
				aboveBullShortLine = true
			}

			// 加仓
			if aboveBullShortLine {
				//overweight = true
				var overOrUnderWeightAmount int = properties.QuantProperties_.OverOrUnderWeightAmount
				// 查询可以加仓的股票（注意不能是最后一个交易日）
				var quantStockTransactRecordArray *model.QuantStockTransactRecordArray = &model.QuantStockTransactRecordArray{}
				b.db.Raw("select t.* from quant_stock_transact_record t "+
					"join stock_transaction_data_all stda on stda.code_=t.stock_code and stda.date_=to_date(?, 'yyyy-mm-dd') "+
					"where t.account_name=? and t.sell_date is null and t.sell_price is null and t.sell_amount is null and t.stock_code not in("+
					"select t1.stock_code from optimize_stock_transact_record t1 "+
					"where t1.sell_date is null and t1.sell_price is null and t1.sell_amount is null) and "+
					"t.stock_code not in("+
					"select si_.code_ from stock_info si_ where si_.last_transaction_date=to_date(?,'yyyy-mm-dd')) "+
					"order by stda.total_market_value asc", transactionDate, optimizeAccount.AccountName, transactionDate).Scan(quantStockTransactRecordArray)
				//"order by stda.circulation_market_value asc", transactionDate, optimizeAccount.AccountName, transactionDate).Scan(quantStockTransactRecordArray)
				//if len(*quantStockTransactRecordArray) == 10 {
				//	io.Infoln("")
				//}
				//if nil != quantStockTransactRecordArray && len(*quantStockTransactRecordArray) < 10 {
				if nil != quantStockTransactRecordArray && len(*quantStockTransactRecordArray) > 0 {
					for _, quantStockTransactRecord := range *quantStockTransactRecordArray {
						if overOrUnderWeightAmount > 0 {
							// 查询股票记录
							var stockTransactionDataAll *model.StockTransactionDataAll
							b.db.Raw("select * from stock_transaction_data_all t where t.code_=? and t.date_=to_date(?,'yyyy-mm-dd')",
								quantStockTransactRecord.StockCode, transactionDate).Scan(&stockTransactionDataAll)
							if stockTransactionDataAll == nil {
								io.Infoln("股票[%s]在日期[%s]没有交易记录，可能是停牌，跳过这只股票", quantStockTransactRecord.StockCode, transactionDate)

								continue
							}

							// 如果股票的收盘价过高，或者资金资产太少，连一手也买不了，则直接查找下一个账号
							if util.CalculateBuyStockFee(stockTransactionDataAll.Code, stockTransactionDataAll.ClosePrice, 100) > float64(optimizeAccount.CapitalAssets) {
								break
							}

							// 如果可以买，则向optimize_stock_transact_record表中插入数据。
							// 计算应该买入股票的数量

							// 应当买入的股票的数量
							var shouldBuyStockNumber int = -1
							if len(*quantStockTransactRecordArray) <= (properties.QuantProperties_.MaxHoldStockNumber - optimizeAccount.HoldStockNumber) {
								shouldBuyStockNumber = len(*quantStockTransactRecordArray)
							} else {
								shouldBuyStockNumber = properties.QuantProperties_.MaxHoldStockNumber - optimizeAccount.HoldStockNumber
							}

							// 判断是否需要继续买入
							if shouldBuyStockNumber == 0 {
								io.Infoln("账号[%s]持股数量已经是%d，不再需要买入股票", optimizeAccount.AccountName, properties.QuantProperties_.MaxHoldStockNumber)
								break
							}

							// 计算买多少股
							// 买入多少股
							var buyOrSellAmount int = 100

							for optimizeAccount.CapitalAssets/float64(properties.QuantProperties_.MaxHoldStockNumber-optimizeAccount.HoldStockNumber) >= util.CalculateBuyStockFee(quantStockTransactRecord.StockCode, stockTransactionDataAll.ClosePrice, buyOrSellAmount) {
								if util.CalculateBuyStockFee(quantStockTransactRecord.StockCode, stockTransactionDataAll.ClosePrice, buyOrSellAmount) >= optimizeAccount.CapitalAssets/float64(properties.QuantProperties_.MaxHoldStockNumber-optimizeAccount.HoldStockNumber) {
									break
								}
								buyOrSellAmount = buyOrSellAmount + 100
							}
							if optimizeAccount.CapitalAssets/float64(properties.QuantProperties_.MaxHoldStockNumber-optimizeAccount.HoldStockNumber) < util.CalculateBuyStockFee(quantStockTransactRecord.StockCode, stockTransactionDataAll.ClosePrice, buyOrSellAmount) {
								if buyOrSellAmount == 100 {
									continue
								} else {
									buyOrSellAmount = buyOrSellAmount - 100
								}
							}

							b.db.Exec("insert into optimize_stock_transact_record(ACCOUNT_NAME, STOCK_CODE, BUY_DATE, BUY_PRICE, BUY_AMOUNT, "+
								"REGISTRATION_FEE_WHEN_BUY, COMMISSION_WHEN_BUY) "+
								"values(?, ?, to_date(?, 'yyyy-mm-dd'), ?, ?, ?, ?)",
								optimizeAccount.AccountName, quantStockTransactRecord.StockCode, transactionDate, stockTransactionDataAll.ClosePrice, buyOrSellAmount,
								util.CalculateRegistrationFee(quantStockTransactRecord.StockCode, buyOrSellAmount),
								util.CalculateCommission(stockTransactionDataAll.ClosePrice, buyOrSellAmount))
							overOrUnderWeightAmount--
						} else {
							break
						}
					}
				}
			}
		}
	}
	//return overweight
}
